//#include "stdafx.h"
#include "base_optex.h"

BOOL CBaseOptex::sm_fUniprocessorHost = -1;

CBaseOptex::CBaseOptex( uint32 nSpinCount /* = 4000 */ )
{
	CommonContructor( nSpinCount, FALSE, NULL );
}
CBaseOptex::CBaseOptex( cstr_t lpszName, uint32 nSpinCount /* = 4000 */ )
{
	CommonContructor( nSpinCount, FALSE, ( void* )lpszName );
}
CBaseOptex::~CBaseOptex( )
{
	CloseHandle( m_hevt );
	if( IsSingleProcessOptex( ) )
	{
		delete m_psi;
	}
	else
	{
		UnmapViewOfFile( m_psi );
		CloseHandle( m_hfm );
	}
}
void CBaseOptex::SetSpinCount( DWORD dwSpinCount )
{
	if( !sm_fUniprocessorHost )
	{
		InterlockedExchangePointer( ( PVOID* )&m_psi->m_dwSpinCount, ( PVOID )( DWORD_PTR )dwSpinCount );
	}
}
void CBaseOptex::Enter( )
{
	if( TryEnter( ) )
	{
		return;
	}
	DWORD dwThreadId = GetCurrentThreadId( );
	if( InterlockedIncrement( &m_psi->m_lLockCount ) == 1 )
	{
		m_psi->m_dwThreadId    = dwThreadId;
		m_psi->m_lRecurseCount = 1;
	}
	else
	{
		if( m_psi->m_dwThreadId == dwThreadId )
		{
			m_psi->m_lRecurseCount++;
		}
		else
		{
			WaitForSingleObject( m_hevt, INFINITE );
			m_psi->m_dwThreadId    = dwThreadId;
			m_psi->m_lRecurseCount = 1;
		}
	}
}
bool CBaseOptex::TryEnter( )
{
	DWORD dwThreadId = GetCurrentThreadId( );
	BOOL  fThisThreadOwnsTheOptex = FALSE;
	DWORD dwSpinCount = m_psi->m_dwSpinCount;
	do{
		fThisThreadOwnsTheOptex = ( 0 == InterlockedCompareExchange( &m_psi->m_lLockCount, 1, 0 ) );
		if( fThisThreadOwnsTheOptex )
		{
			m_psi->m_dwThreadId    = dwThreadId;
			m_psi->m_lRecurseCount = 1;
		}
		else
		{
			if( m_psi->m_dwThreadId == dwThreadId )
			{
				InterlockedIncrement( &m_psi->m_lLockCount );
				m_psi->m_lRecurseCount++;
				fThisThreadOwnsTheOptex = TRUE;
			}
		}
	}while( !fThisThreadOwnsTheOptex && ( dwSpinCount-- ) > 0 );

	return ( fThisThreadOwnsTheOptex==TRUE );
}
void CBaseOptex::Leave( )
{
	m_psi->m_lRecurseCount--;
	if( m_psi->m_lRecurseCount > 0 )
	{
		InterlockedDecrement( &m_psi->m_lLockCount );
	}
	else
	{
		m_psi->m_dwThreadId = 0;
		if( InterlockedDecrement( &m_psi->m_lLockCount ) > 0 )
		{
			SetEvent( m_hevt );
		}
	}
}
bool CBaseOptex::IsSingleProcessOptex( ) const
{
	return ( m_hfm==NULL );
}

void CBaseOptex::CommonContructor( uint32 nSpinCount, bool bUnicode, void * pszName )
{
	if( sm_fUniprocessorHost == -1 )
	{
		SYSTEM_INFO sinf;
		GetSystemInfo( &sinf );
		sm_fUniprocessorHost = ( sinf.dwNumberOfProcessors == 1 );
	}
	m_hevt = m_hfm = m_psi = NULL;
	if( pszName == NULL )
	{
		m_hevt = CreateEvent( NULL, FALSE, FALSE, NULL );
		m_psi  = new SHAREDINFO;
		ZeroMemory( m_psi, sizeof( SHAREDINFO ) );
	}
	else
	{
		char_t szResult[100];
		ConstructObjectName( szResult, _T("Optex_Event_"), bUnicode, pszName );
		m_hevt = CreateEvent( NULL, FALSE, FALSE, szResult );
		ConstructObjectName( szResult, _T("Optex_Event_"), bUnicode, pszName );
		m_hfm = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof( *m_psi ), szResult );
		m_psi = ( PSHAREDINFO )MapViewOfFile( m_hfm, FILE_MAP_WRITE, 0, 0, 0 );
	}
	SetSpinCount( nSpinCount );
}
char_t * CBaseOptex::ConstructObjectName( char_t * pszResult, cstr_t pszPrefix, bool bUnicode, void * pszName )
{
	pszResult[0] = 0;
	if( pszName == NULL )
	{
		return NULL;
	}
	wsprintf( pszResult, bUnicode ? _T("%s%S") : _T("%s%s"), pszPrefix, pszName );
	return pszResult;
}